// -------------------------------------------------
// BlinKit - BlinKit Library
// -------------------------------------------------
//   File Name: tooltip.cpp
// Description: Tooltip Class
//      Author: Ziming Li
//     Created: 2022-04-17
// -------------------------------------------------
// Copyright (C) 2022 MingYang Software Technology.
// -------------------------------------------------

#include "./tooltip.h"

static constexpr double TimerDelay = 1.0;

namespace BlinKit {

Tooltip::Tooltip(HWND hParent)
    : m_hWnd(CreateTooltipWindow(hParent))
    , m_timer(this, &Tooltip::TimerFired)
{
    ASSERT(nullptr != m_hWnd);
}

Tooltip::~Tooltip(void)
{
    DestroyWindow(m_hWnd);
}

HWND Tooltip::CreateTooltipWindow(HWND hParent)
{
    return CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, nullptr,
        WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        hParent, nullptr, theModule, nullptr);
}

void Tooltip::Hide(void)
{
    if (0 == m_cookie)
        return;

    TOOLINFO ti = { 0 };
    ti.cbSize   = sizeof(TOOLINFO);
    ti.uId      = m_cookie;
    ti.hwnd     = GetParent(m_hWnd);
    SendMessage(m_hWnd, TTM_DELTOOL, 0, reinterpret_cast<LPARAM>(&ti));

    m_cookie = 0;
    SendMessage(m_hWnd, TTM_TRACKACTIVATE, FALSE, 0);
}

bool Tooltip::ProcessShowNotify(HWND hWnd)
{
    if (hWnd != m_hWnd)
        return false;

    RECT rc;
    GetWindowRect(m_hWnd, &rc);

    bool shouldMove = false;
    const int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    if (screenWidth < rc.right)
    {
        rc.left -= rc.right - screenWidth;
        shouldMove = true;
    }
    if (GetSystemMetrics(SM_CYSCREEN) < rc.bottom)
    {
        rc.top -= GetSystemMetrics(SM_CYCURSOR) * 2; // Move above.
        shouldMove = true;
    }

    if (!shouldMove)
        return false;

    SetWindowPos(m_hWnd, nullptr, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
    return true;
}

void Tooltip::Show(std::wstring &&text, TextDirection dir, unsigned long cookie)
{
    if (0 != m_cookie)
    {
        if (m_cookie == cookie)
            return;
        Hide();
    }

    m_cookie  = cookie;
    m_text    = std::move(text);
    m_rtlFlag = RTL == dir ? TTF_RTLREADING : 0;

    m_timer.startOneShot(TimerDelay, BLINK_FROM_HERE);
}

void Tooltip::TimerFired(Timer<Tooltip> *)
{
    if (0 == m_cookie)
        return;

    TOOLINFOW ti = { 0 };
    ti.cbSize    = sizeof(TOOLINFOW);
    ti.uFlags    = TTF_TRACK | TTF_ABSOLUTE | m_rtlFlag;
    ti.uId       = m_cookie;
    ti.hwnd      = GetParent(m_hWnd);
    ti.lpszText  = const_cast<PWSTR>(m_text.c_str());
    SendMessage(m_hWnd, TTM_ADDTOOLW, 0, reinterpret_cast<LPARAM>(&ti));

    POINT pt;
    GetCursorPos(&pt);
    pt.y += GetSystemMetrics(SM_CYCURSOR);
    SendMessage(m_hWnd, TTM_TRACKPOSITION, 0, MAKELPARAM(pt.x, pt.y));

    SendMessage(m_hWnd, TTM_TRACKACTIVATE, TRUE, reinterpret_cast<LPARAM>(&ti));
}

} // namespace BlinKit
